﻿using System;
using System.Linq;

namespace StreetPacMan.Server.Rules
{
    public interface IAddingPlayersRules
    {
        void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role);
    }
    public class GameMustExistRule : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            var gameExists= pacManDataContext.Games.Any(x => x.Name == gameName);
            if(gameExists==false)
            {
                throw new ArgumentException(string.Format("Game '{0}' does not exists", gameName));
            }
        }
    }
    public class GameMustNotHaveStarted : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            var gameStateEnum = pacManDataContext
                .Games
                .Single(x => x.Name == gameName)
                .StateEnum;
            bool valigGameState = gameStateEnum == GameState.Created || 
                gameStateEnum == GameState.WaitingForMorePlayersToJoin;
            if(valigGameState==false)
            {
                throw  new InvalidOperationException(string.Format("Game '{0}' state is {1}, and you cannot join it",  gameName, gameStateEnum));
            }
        }
    }

    public class PlayerNameIsNotEmpty : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            if (string.IsNullOrEmpty(entityName))
            {
                throw new ArgumentException("Player name must not be null or empty string");
            }
        }
    }

    public class NoPlayerWithExistingName : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            var allPlayersHaveDifferentNames = pacManDataContext
                .Games
                .Single(x => x.Name == gameName)
                .Players
                .All(x => x.Name != entityName);
            if (allPlayersHaveDifferentNames == false)
            {
                throw new InvalidOperationException(string.Format("There is already a player called {0} in the game", entityName));
            }
        }
    }

    public class OnlyThreePacMenAllowedRule : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            if (role != PlayerRole.PacMan)
            {
                return ;
            }
            var tooManyPacMen = pacManDataContext
                .Games
                .Single(x => x.Name == gameName)
                .Players
                .Where(x => x.RoleEnum == PlayerRole.PacMan)
                .Count() >= 3;
            if (tooManyPacMen)
            {
                throw new InvalidOperationException("There are already 8 ghosts in the game. Cannot join as ghost.");
            }
        }
    }
    public class OnlyEightGhostsAllowedRule : IAddingPlayersRules
    {
        public void ThrowErrorIfInvalid(PacManDataContext pacManDataContext, string gameName, string entityName, PlayerRole role)
        {
            if (role != PlayerRole.Ghost)
            {
                return ;
            }
            var tooManyGhosts=  pacManDataContext
                .Games
                .Single(x => x.Name == gameName)
                .Players
                .Where(x => x.RoleEnum == PlayerRole.Ghost)
                .Count() >= 8;
            if(tooManyGhosts)
            {
                throw new InvalidOperationException("There are already 8 ghosts in the game. Cannot join as ghost.");
            }
        }
    }
}